home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / ARGONET / PD / MATHS / RLAB / RLAB125.ZIP / !RLaB / misc / plplot < prev    next >
Text File  |  1996-04-09  |  58KB  |  2,618 lines

  1. #
  2. # New plot.r for use with PLPLOT library.
  3. # The help files for these functions are in
  4. # misc/plhelp
  5. #
  6.  
  7. # plplot.r
  8.  
  9. # This file is a part of RLaB ("Our"-LaB)
  10. # Copyright (C) 1994  Ian R. Searle
  11.  
  12. # This program is free software; you can redistribute it and/or modify
  13. # it under the terms of the GNU General Public License as published by
  14. # the Free Software Foundation; either version 2 of the License, or
  15. # (at your option) any later version.
  16.  
  17. # This program is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. # GNU General Public License for more details.
  21.  
  22. # You should have received a copy of the GNU General Public License
  23. # along with this program; if not, write to the Free Software
  24. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26. # See the file ../COPYING
  27.  
  28. #
  29. # If your system does not deal with Infs and NaNs well, then
  30. # uncomment the following lines.
  31. #
  32.  
  33. # static (isinf, isnan)
  34. #
  35. # isinf = function ( A ) { return (0); };
  36. # isnan = function ( A ) { return (0); };
  37.  
  38. static (WIN)        # The static plot window structure
  39. static (P)        # The active/current plot window
  40.  
  41. #
  42. # Maintain the transformations for 3-D plots.
  43. #
  44.  
  45. static (basex, basey, height)
  46. basex = 2;
  47. basey = 2;
  48. height = 4;
  49.  
  50. #
  51. # Static (private) functions. For use from within
  52. # this file only.
  53. #
  54.  
  55. static (create_plot_object)
  56. static (check_plot_object)
  57. static (xy_scales)
  58. static (x_scales)
  59. static (y_scales)
  60. static (z_scales)
  61. static (XYZ_scales)
  62. static (list_scales)
  63. static (list_sort)
  64. static (hist_scales)
  65. static (plot_matrix)
  66. static (plot_list)
  67. static (check_3d_list)
  68. static (find_char)
  69. static (get_style)
  70. static (make_legend)
  71. static (plhold_first)
  72.  
  73. #
  74. # Defaults
  75. #
  76.  
  77. static (grid_x_default, grid_y_default)
  78. static (grid_3x_default, grid_3y_default, grid_3z_default)
  79.  
  80. grid_x_default = "bcnst";
  81. grid_y_default = "bcnstv";
  82. grid_3x_default = "bnstu";
  83. grid_3y_default = "bnstu";
  84. grid_3z_default = "bcdmnstuv";
  85.  
  86. static (subplot_f)
  87. subplot_f = 0;
  88.  
  89. #
  90. # Create the default plot-object.
  91. # Initialize to all the default values
  92. #
  93.  
  94. if (!exist (WIN)) 
  95. {
  96.   # Create the plot-object list
  97.   WIN = <<>>;
  98. }
  99.  
  100. create_plot_object = function ( N, nx, ny )
  101. {
  102.   if (!exist (N)) { N = 0; }
  103.   
  104.   pobj = <<>>;
  105.   pobj.subplot = 0;        # The current subplot no.
  106.   pobj.nplot = nx*ny;        # Total no. of plots on window
  107.   
  108.   pobj.fontld = 0;        # Loaded extended fonts?
  109.   
  110.   for (i in 1:(nx*ny))
  111.   {
  112.     pobj.style.[i] = "line";    # The type/style of plot to draw
  113.     pobj.nbin[i] = 1j;          # The number of bins for a histogram
  114.     pobj.width[i] = 1;        # The pen width for current plot
  115.     pobj.font[i] = 1;        # The current font
  116.     pobj.xlabel[i] = "";
  117.     pobj.ylabel[i] = "";
  118.     pobj.zlabel[i] = "";
  119.     pobj.title[i] = "";
  120.     pobj.orientation[i] = "portrait";
  121.     pobj.desc.[i] = "default";        # The legend description
  122.     pobj.gridx[i] =  grid_x_default;    # Plot axes style, 2D-X
  123.     pobj.gridy[i] =  grid_y_default;    # Plot axes style, 2D-Y
  124.     pobj.grid3x[i] = grid_3x_default;    # Plot axes style, 3D-X
  125.     pobj.grid3y[i] = grid_3y_default;    # Plot axes style, 3D-Y
  126.     pobj.grid3z[i] = grid_3z_default;    # Plot axes style, 3D-Z
  127.     pobj.aspect[i] = 0;                # Plot aspect style
  128.     pobj.alt[i] = 60;
  129.     pobj.az[i] = 45;
  130.     
  131.     pobj.xmin[i] = 1j;
  132.     pobj.xmax[i] = 1j;
  133.     pobj.ymin[i] = 1j;
  134.     pobj.ymax[i] = 1j;
  135.     pobj.zmin[i] = 1j;
  136.     pobj.zmax[i] = 1j;
  137.     
  138.     pobj.page.xp = 0;
  139.     pobj.page.yp = 0;
  140.     pobj.xleng = 400;
  141.     pobj.yleng = 300;
  142.     pobj.xoff = 200;
  143.     pobj.yoff = 200;
  144.  
  145.     pobj.color[i;] = 1:14;               # 14 possible colors...
  146.     pobj.lstyle[i;] = 1:8;               # 8 possible line styles...
  147.     pobj.pstyle[i;] = 1:8;               # 8 possible point styles...
  148.   }
  149.   
  150.   #
  151.   # Save the newly generated plot-object
  152.   # in a list of plot-objects.
  153.   
  154.   WIN.[N] = pobj;
  155. };
  156.  
  157. ##############################################################################
  158. #
  159. # Check to make sure a plot-object exists. If one
  160. # does not exist, create it.
  161. #
  162.  
  163. check_plot_object = function ()
  164. {
  165.   if (length (WIN) == 0)
  166.   {
  167.     plstart();
  168.     return 0;
  169.   }
  170.   return 1;
  171. };
  172.  
  173. ##############################################################################
  174. #
  175. # Set the current plot window
  176. # Default value = 0
  177. #
  178.  
  179. plwin = function ( N )
  180. {
  181.   check_plot_object ();
  182.   if (!exist (N)) { N = 0; }
  183.   
  184.   # Check to make sure N is valid
  185.   
  186.   for (i in members (WIN))
  187.   {
  188.     if (N == strtod (i))
  189.     {
  190.       _plsstrm (N);
  191.       return P = N;
  192.     }
  193.   }
  194.   printf ("plwin: invalid argument, N = %i\n", N);
  195.   printf ("      valid values are:\n");
  196.   WIN?
  197. };
  198.  
  199. ##############################################################################
  200. #
  201. # Show the current plot-window, and the possibilities
  202. #
  203.  
  204. showplwin = function ( all )
  205. {
  206.   if (length (WIN) == 0)
  207.   {
  208.     printf ("No plot objects\n");
  209.     return 0;
  210.   }
  211.   
  212.   printf ("Current plot-window is:\t\t%i\n", P);
  213.   printf ("Available plot windows are:\t");
  214.   for (i in members (WIN))
  215.   {
  216.     printf ("%s   ", i);
  217.   }
  218.   printf ("\n");
  219.  
  220.   if (exist (all))
  221.   {
  222.     for (i in members (WIN.[P]))
  223.     {
  224.       WIN.[P].[i]
  225.     }
  226.   }
  227. };
  228.  
  229. getplot = function ( win_no )
  230. {
  231.   local (win_no)
  232.  
  233.   if (length (WIN) != 0)
  234.   {
  235.     if (!exist (win_no)) { win_no = P; }
  236.  
  237.     if (exist (WIN.[win_no]))
  238.     {
  239.       return (WIN.[win_no]);
  240.     else
  241.       return 0;
  242.     }
  243.   }
  244.   return <<>>;
  245. };
  246.  
  247.  
  248. ##############################################################################
  249. #
  250. # Set the plot-window orientation (portrait, landscape, rotated).
  251. #
  252.  
  253. plsori = function ( rot )
  254. {
  255.   _plsori (rot);
  256. };
  257.  
  258. ##############################################################################
  259. #
  260. # Set/start/select the plot device
  261. #
  262.  
  263. plstart = function ( nx, ny, dev )
  264. {
  265.   if (!exist (nx)) { nx = 1; }
  266.   if (!exist (ny)) { ny = 1; }
  267.   if (!exist (dev)) { dev = "?"; }
  268.   
  269.   # Create the plot-object
  270.   # First, figure out the index
  271.   if (!exist (P))
  272.   {
  273.     P = 0;
  274.   else
  275.     P = P + 1;
  276.   }
  277.   
  278.   create_plot_object (P, nx, ny);
  279.   _plsstrm (P);
  280.   
  281.   #_plscolbg (255,255,255); # white
  282.   # Default window size for X
  283.   _plspage (0, 0, 400, 300, 200, 200);
  284.   
  285.   # Start up the plot-window
  286.   _plstart (dev, nx, ny);
  287.   
  288.   _plwid (8);
  289.   
  290.   # Turn between plot pause off
  291.   _plspause (0);
  292.   _pltext ();
  293.   
  294.   return P;
  295. };
  296.  
  297. ##############################################################################
  298. #
  299. # Close a plot device. We must destroy the current plot-object
  300. # And switch the output stream back to the default.
  301. #
  302.  
  303. plclose = function ()
  304. {
  305.   if (size (WIN) > 1)
  306.   {   
  307.     #
  308.     # Clear WIN.[P] and reset P to 1st plot-window
  309.     #
  310.  
  311.     clear (WIN.[P]);
  312.     _plend1 ();
  313.     _plsstrm (strtod (members (WIN)[1]));
  314.     P = strtod (members (WIN)[1]);
  315.     return P;
  316.  
  317.   else if (size (WIN) == 1) {
  318.  
  319.     if (exist (WIN.[P])) 
  320.     { 
  321.       clear (WIN.[P]); 
  322.       clear (P);
  323.     }
  324.     _plend1 ();
  325.     return 1;
  326.  
  327.   else if (size (WIN) == 0) {
  328.  
  329.     return 0;
  330.  
  331.   } } }
  332. };
  333.  
  334. ##############################################################################
  335. #
  336. # Close ALL the plot-windows
  337. #
  338.  
  339. plend = function ()
  340. {
  341.   _plend ();
  342.   if (exist (WIN)) { clear (WIN); }
  343.   if (exist (P)) { clear (P); }
  344.   WIN = <<>>;
  345. };
  346.  
  347. ##############################################################################
  348. #
  349. # Change plot aspect ratio
  350. #
  351.  
  352. plaspect = function ( aspect )
  353. {
  354.   check_plot_object ();
  355.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  356.   if (!exist (aspect))
  357.   {
  358.     WIN.[P].aspect[i] = 0;
  359.   else
  360.     WIN.[P].aspect[i] = aspect;
  361.   }
  362. };
  363.  
  364. ##############################################################################
  365. #
  366. # Change plot line style
  367. #
  368.  
  369. plstyle = function ( style )
  370. {
  371.   check_plot_object ();
  372.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  373.  
  374.   if (exist (style)) 
  375.   {
  376.     if (class (style) == "string") 
  377.     {
  378.       for (j in 1:style.n)
  379.       {
  380.     if (style[j] != "line" && ...
  381.             style[j] != "point" && ...
  382.             style[j] != "line-point")
  383.     {
  384.       error ("plstyle: STYLE must be either " + ...
  385.              "\"point\", \"line\" or \"line-point\"");
  386.     }
  387.       }
  388.       WIN.[P].style.[i] = style;
  389.     }
  390.     return 1;
  391.   }
  392.   WIN.[P].style.[i] = "line";
  393.   return 1;
  394. };
  395.  
  396. ##############################################################################
  397. #
  398. # Control of the plot line style.
  399. # There are 8 line styles
  400.  
  401. plline = function ( line_style )
  402. {
  403.   check_plot_object ();
  404.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  405.  
  406.   if (exist (line_style)) 
  407.   {
  408.     if (class (line_style) == "num") 
  409.     {
  410.       if (line_style.nc != 8)
  411.       {
  412.     error ("plpoint: LVEC must be 1x8 in size");
  413.       }
  414.       WIN.[P].lstyle[i;] = line_style;
  415.     }
  416.     return 1;
  417.   }
  418.   WIN.[P].lstyle[i;] = 1:8;
  419.   return 1;
  420. };
  421.  
  422. ##############################################################################
  423. #
  424. # Control of the plot point style.
  425. # There are 8 line styles
  426.  
  427. plpoint = function ( point_style )
  428. {
  429.   check_plot_object ();
  430.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  431.  
  432.   if (exist (point_style)) 
  433.   {
  434.     if (class (point_style) == "num") 
  435.     {
  436.       if (point_style.nc != 8)
  437.       {
  438.     error ("plpoint: PVEC must be 1x8 in size");
  439.       }
  440.       WIN.[P].pstyle[i;] = point_style;
  441.     }
  442.     return 1;
  443.   }
  444.   WIN.[P].pstyle[i;] = 1:8;
  445.   return 1;
  446. };
  447.  
  448. ##############################################################################
  449. #
  450. # Get the right value of line-style
  451. #
  452.  
  453. get_style = function ( STY, K )
  454. {
  455.   local (sty);
  456.   sty = mod(K, STY.n);
  457.   if(sty == 0) 
  458.   { 
  459.     sty = STY.n; 
  460.   }
  461.   return STY[sty];
  462. };
  463.  
  464. ##############################################################################
  465. #
  466. # Change fonts
  467. #
  468.  
  469. plfont = function ( font )
  470. {
  471.   check_plot_object ();
  472.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  473.   
  474.   if (!exist (font)) { font = 1; }
  475.   
  476.   if (WIN.[P].fontld == 0)
  477.   {
  478.     _plfontld (1);
  479.     WIN.[P].fontld = 1;
  480.   }
  481.   
  482.   WIN.[P].font[i] = font;
  483.   return P;
  484. };
  485.  
  486. ##############################################################################
  487. #
  488. # Change pen width
  489. #
  490.  
  491. plwid = function ( width )
  492. {
  493.   check_plot_object ();
  494.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  495.   
  496.   if (!exist (width)) { width = 1; }
  497.   WIN.[P].width[i] = width;
  498.   return P;
  499. };
  500.  
  501. ##############################################################################
  502. #
  503. # Place some text on the plot
  504. #
  505.  
  506. plptex = function ( text, x , y , dx , dy , just )
  507. {
  508.   if (!check_plot_object ()) 
  509.   {
  510.     printf ("Must use plot() before plptex()\n");
  511.     return 0;
  512.   }
  513.   
  514.   if (!exist (x)) { x = 0; }
  515.   if (!exist (y)) { y = 0; }
  516.   if (!exist (dx)) { dx = abs(x)+1; }
  517.   if (!exist (dy)) { dy = 0; }
  518.   if (!exist (just)) { just = 0; }
  519.   
  520.   _plptex (x, y, dx, dy, just, text);
  521. };
  522.  
  523. ##############################################################################
  524. #
  525. # Set up the viewing altitude for 3-D plots
  526. #
  527.  
  528. plalt = function ( ALT )
  529. {
  530.   check_plot_object ();
  531.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  532.  
  533.   if (exist (ALT)) 
  534.   { 
  535.     WIN.[P].alt[i] = ALT; 
  536.   else
  537.     WIN.[P].alt[i] = 60;
  538.   }
  539.   return P;
  540. };
  541.  
  542. ##############################################################################
  543. #
  544. # Set the viewing azimuth for 3-D plots
  545. #
  546.  
  547. plaz = function ( AZ )
  548. {
  549.   check_plot_object ();
  550.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  551.  
  552.   if (exist (AZ)) 
  553.   { 
  554.     WIN.[P].az[i] = AZ; 
  555.   else
  556.     WIN.[P].az[i] = 45;
  557.   }
  558.   return P;
  559. };
  560.  
  561. ##############################################################################
  562. #
  563. # Find a character in a string
  564. #
  565.  
  566. find_char = function ( str , char )
  567. {  
  568.   tmp = strsplt (str);
  569.   for (i in 1:tmp.n)
  570.   {
  571.     if (tmp[i] == char) 
  572.     {
  573.       return i;
  574.     }
  575.   }
  576.   return 0;
  577. };
  578.  
  579. ##############################################################################
  580. #
  581. # Sort list element names/labels by numeric order, then string order.
  582. #
  583.  
  584. list_sort = function ( L )
  585. {
  586.   tl = <<>>;
  587.   j = k = 1;
  588.  
  589.   for (i in members (L))
  590.   {
  591.     if (!isnan (strtod (i)))
  592.     {
  593.       num[j] = i;
  594.       j++;
  595.       else
  596.       char[k] = i;
  597.       k++;
  598.     }
  599.   }
  600.   
  601.   # Sort the numeric labels
  602.   
  603.   if (exist (num))
  604.   {
  605.     num = sort (strtod (num)).val;
  606.     tl.num = num;
  607.   }
  608.  
  609.   if (exist (char))
  610.   {
  611.     tl.char = char;
  612.   }
  613.  
  614.   return tl;
  615. };
  616.  
  617. ##############################################################################
  618. #
  619. # Set the subplot, this overides the action in plot().
  620. #
  621.  
  622. subplot = function ( sub )
  623. {
  624.   check_plot_object ();
  625.   
  626.   if (!exist (sub))
  627.   {
  628.     subplot_f = 0;
  629.     _pladv (0);
  630.   else
  631.     if (sub > WIN.[P].nplot)
  632.     {
  633.       error ("Current window does not have this many subplots");
  634.     }
  635.     if (sub > 0)
  636.     {
  637.       WIN.[P].subplot = sub - 1;
  638.       subplot_f = 1;
  639.       _pladv (sub);
  640.     else
  641.       if (sub == 0)
  642.       {
  643.         # Do not advance, stay at current subplot
  644.         WIN.[P].subplot = WIN.[P].subplot - 1;
  645.         subplot_f = 1;
  646.       }
  647.     }
  648.   }
  649. };
  650.  
  651. ##############################################################################
  652. #
  653. # Plot the columns of a matrix (X-Y plot).
  654. #
  655. ##############################################################################
  656.  
  657. plot = function ( data, key, textf )
  658. {
  659.   check_plot_object ();
  660.   
  661.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  662.   if (!exist (key)) { key = 1; }
  663.   if (!exist (textf)) { textf = 1; }
  664.  
  665.   #
  666.   # Draw the graph
  667.   # Step through the matrix plotting
  668.   # each column versus the 1st
  669.   #
  670.   
  671.   if (class (data) == "num")
  672.   {
  673.     #
  674.     # Set up the plot basics
  675.     #
  676.  
  677.     if (abs (key) > data.nc)
  678.     {
  679.       error_1 ("plot: KEY argument > M.nc");
  680.     }
  681.     
  682.     _plgra ();
  683.     _plcol (1);
  684.     _pllsty (1);
  685.     _plfont (WIN.[P].font[p]);
  686.     _plwid (WIN.[P].width[p]);
  687.  
  688.     if (!subplot_f) 
  689.     {
  690.       _pladv (0);        # Advance 1 subplot
  691.     else
  692.       subplot_f = 0;     # The user has set the subplot
  693.     }
  694.  
  695.     if (WIN.[P].aspect[p] != 0)
  696.     {
  697.       _plvasp (WIN.[P].aspect[p]);
  698.     else
  699.       _plvsta ();
  700.     }
  701.     
  702.     #
  703.     # Compute scale limits
  704.     #
  705.  
  706.     k = find ((1:data.nc) != abs (key));
  707.     if (key > 0)
  708.     {
  709.       if (data.nc != 1)
  710.       {
  711.     x_scales ( real(data)[;key], p, xmin, xmax );
  712.     y_scales ( real(data)[;k],   p, ymin, ymax );
  713.       else
  714.     x_scales ( (1:data.nr)', p, xmin, xmax );
  715.     y_scales ( real(data),   p, ymin, ymax );
  716.       }
  717.     else if (key < 0) {
  718.       x_scales ( real(data)[;k],   p, xmin, xmax );
  719.       y_scales ( real(data)[;abs(key)], p, ymin, ymax );
  720.     else
  721.       x_scales ( (1:data.nr)', p, xmin, xmax );
  722.       y_scales ( real(data),   p, ymin, ymax );
  723.     } }
  724.  
  725.     _plwind (xmin, xmax, ymin, ymax);
  726.     _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  727.     if (plot_matrix ( data, key, p, 0, xmin, xmax, ymin, ymax, ymax-ymin ) < 0) 
  728.     {
  729.       return -1;
  730.     }
  731.     
  732.     else if (class (data) == "list") {
  733.       
  734.       _plgra ();
  735.       _plcol (1);
  736.       _pllsty (1);
  737.       _plfont (WIN.[P].font[p]);
  738.       _plwid (WIN.[P].width[p]);
  739.  
  740.       list_scales ( data, key, p, xmin, xmax, ymin, ymax );
  741.  
  742.       if (!subplot_f) 
  743.       {
  744.     _pladv (0);        # Advance 1 subplot
  745.       else
  746.     subplot_f = 0;     # The user has set the subplot
  747.       }
  748.  
  749.       if (WIN.[P].aspect[p] != 0)
  750.       {
  751.     _plvasp (WIN.[P].aspect[p]);
  752.       else
  753.        _plvsta ();
  754.       }
  755.       
  756.       _plwind (xmin, xmax, ymin, ymax);
  757.       _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  758.       if (plot_list ( data, key, p, xmin, xmax, ymin, ymax ) < 0) 
  759.       { 
  760.     return -1;
  761.       }
  762.  
  763.     else
  764.       error ("plot: un-acceptable argument");
  765.   } }
  766.  
  767.   _pllsty (1);
  768.   _plcol (1);
  769.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  770.   _plflush ();
  771.   if (textf)
  772.   {
  773.     _pltext ();
  774.   }
  775.   
  776.   #
  777.   # Increment the plot no. so that next time
  778.   # we use the correct settings.
  779.   #
  780.   
  781.   WIN.[P].subplot = WIN.[P].subplot + 1;
  782.   return P;
  783. };
  784.  
  785. #
  786. # plhold:
  787. # Plot some data, and "hold" on for more.
  788. # Plot the data, setting up the plot as usual the first time.
  789. # On subsequent plots do not do any setup, just plot some
  790. # more. plhold_off must be called to finish up.
  791. #
  792.  
  793. plhold_first = 1;    # True (1) if plhold() has NOT been used.
  794.                         # Or if plhold_off() has been used.
  795.             # False (0) if plhold is in use
  796.  
  797. static (hxmin, hxmax, hymin, hymax)
  798.  
  799. plhold = function ( data, key )
  800. {
  801.   check_plot_object ();
  802.   
  803.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  804.   if (!exist (key)) { key = 1; }
  805.   if (abs (key) > data.nc)
  806.   {
  807.     error_1 ("plot: KEY argument > M.nc");
  808.   }
  809.   
  810.   if (plhold_first)
  811.   {
  812.     if (class (data) == "num")
  813.     {
  814.       #
  815.       # Do the setup ONCE
  816.       #
  817.       hxmin = hxmax = hymin = hymax = 0;
  818.       _plgra ();
  819.       _plcol (1);
  820.       _pllsty (1);
  821.       _plfont (WIN.[P].font[p]);
  822.       _plwid (WIN.[P].width[p]);
  823.  
  824.       if (!subplot_f) 
  825.       {
  826.     _pladv (0);        # Advance 1 subplot
  827.       else
  828.     subplot_f = 0;     # The user has set the subplot
  829.       }
  830.  
  831.       if (WIN.[P].aspect[p] != 0)
  832.       {
  833.     _plvasp (WIN.[P].aspect[p]);
  834.       else
  835.     _plvsta ();
  836.       }
  837.  
  838.       xy_scales ( real(data), p, hxmin, hxmax, hymin, hymax );
  839.       
  840.       k = find ((1:data.nc) != abs (key));
  841.       if (key > 0)
  842.       {
  843.     x_scales ( real(data)[;key], p, xmin, xmax );
  844.     if (data.nc != 1)
  845.     {
  846.       y_scales ( real(data)[;k],   p, ymin, ymax );
  847.         else
  848.       y_scales ( (1:data.nr)',   p, ymin, ymax );
  849.     }
  850.       else if (key < 0) {
  851.     x_scales ( real(data)[;k],   p, xmin, xmax );
  852.     y_scales ( real(data)[;abs(key)], p, ymin, ymax );
  853.       else
  854.     x_scales ( (1:data.nr)', p, xmin, xmax );
  855.     y_scales ( real(data),   p, ymin, ymax );
  856.       } }
  857.  
  858.       _plwind (hxmin, hxmax, hymin, hymax);
  859.       _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  860.       _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);
  861.     else
  862.       error ("plot: un-acceptable argument");
  863.     }
  864.     plhold_first = 0;
  865.   }
  866.   
  867.   if (plot_matrix ( data, key, p, 0, hxmin, hxmax, hymin, hymax, hymax-hymin ) < 0) 
  868.   { 
  869.     return -1; 
  870.   }
  871.  
  872.   _plcol (1);
  873.   _plflush ();
  874.   _pltext ();
  875.  
  876.   return P;
  877. };
  878.  
  879. ##############################################################################
  880. #
  881. # Clean up the plotting environment and get ready
  882. # for normal interactive usage.
  883. #
  884.  
  885. plhold_off = function ( )
  886. {
  887.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  888.   plhold_first = 1;  
  889.   _plcol (1);
  890.   _plflush ();
  891.   _pltext ();
  892.   WIN.[P].subplot = WIN.[P].subplot + 1;
  893.   return P;
  894. };
  895.  
  896. ##############################################################################
  897. #
  898. # Plot a 3-Dimensional graph. The data is composed in a list, with
  899. # elements `x', `y', and `z'. x and y are single-dimension arrays
  900. # (row or column matrices), and z is a two-dimensional array. The
  901. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  902. # the array x can be thought of a "row-labels", and the values of y
  903. # can be thought of as "column-lables" for the 2-dimensioal array z.
  904. #
  905. # At present plot3 can plot 3 distinct lists. Each list may have
  906. # different X, Y, and Z scales.
  907. #
  908. ##############################################################################
  909.  
  910. plot3 = function ( L31, L32, L33 )
  911. {
  912.   check_plot_object ();
  913.  
  914.   #
  915.   # 1st check list contents
  916.   #
  917.   
  918.   if (exist (L31)) { check_3d_list (L31); }
  919.   if (exist (L32)) { check_3d_list (L32); }
  920.   if (exist (L33)) { check_3d_list (L33); }
  921.   
  922.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  923.  
  924.   #
  925.   # Figure out the scale limits. 
  926.   # Needs improvement!
  927.   #
  928.   
  929.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  930.   if (exist (L31)) 
  931.   {
  932.     XYZ_scales (L31.x, L31.y, L31.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  933.     xmin = Xmin; xmax = Xmax;
  934.     ymin = Ymin; ymax = Ymax;
  935.     zmin = Zmin; zmax = Zmax;
  936.   }
  937.   if (exist (L32)) 
  938.   {
  939.     XYZ_scales (L32.x, L32.y, L32.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  940.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  941.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  942.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  943.   }   
  944.   if (exist (L33)) 
  945.   {
  946.     XYZ_scales (L33.x, L33.y, L33.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  947.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  948.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  949.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  950.   }
  951.   
  952.   _plgra ();
  953.   _plcol (1);
  954.   _pllsty (1);
  955.   _plfont (WIN.[P].font[p]);
  956.   _plwid (WIN.[P].width[p]);
  957.   
  958.   # basex = 2; basey = 2; height = 4;
  959.   xmin2d = -2.0; xmax2d = 2.0;
  960.   ymin2d = -3.0; ymax2d = 5.0;
  961.   
  962.   _plenv (xmin2d, xmax2d, ymin2d, ymax2d, 0, -2);
  963.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  964.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  965.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  966.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  967.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  968.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  969.  
  970.   if (exist (L31))
  971.   {
  972.     if (find_char (WIN.[P].grid3x[p], "l"))
  973.     { x = log10 (real (L31.x)); else x = real (L31.x); }
  974.     if (find_char (WIN.[P].grid3y[p], "l"))
  975.     { y = log10 (real (L31.y)); else y = real (L31.y); }
  976.     if (find_char (WIN.[P].grid3z[p], "l"))
  977.     { z = log10 (real (L31.z)); else z = real (L31.z); }
  978.     
  979.     _plcol (2);
  980.     _plot3d (x, y, z, L31.x.n, L31.y.n, 3, 0);
  981.   }
  982.   if (exist (L32))
  983.   {
  984.     if (find_char (WIN.[P].grid3x[p], "l"))
  985.     { x = log10 (real (L32.x)); else x = real (L32.x); }
  986.     if (find_char (WIN.[P].grid3y[p], "l"))
  987.     { y = log10 (real (L32.y)); else y = real (L32.y); }
  988.     if (find_char (WIN.[P].grid3z[p], "l"))
  989.     { z = log10 (real (L32.z)); else z = real (L32.z); }
  990.     
  991.     _plcol (3);
  992.     _pllsty (2);
  993.     _plot3d (x, y, z, L32.x.n, L32.y.n, 3, 0);
  994.   }
  995.   if (exist (L33)) 
  996.   {
  997.     if (find_char (WIN.[P].grid3x[p], "l"))
  998.     { x = log10 (real (L33.x)); else x = real (L33.x); }
  999.     if (find_char (WIN.[P].grid3y[p], "l"))
  1000.     { y = log10 (real (L33.y)); else y = real (L33.y); }
  1001.     if (find_char (WIN.[P].grid3z[p], "l"))
  1002.     { z = log10 (real (L33.z)); else z = real (L33.z); }
  1003.     
  1004.     _plcol (4);
  1005.     _pllsty (3);
  1006.     _plot3d (x, y, z, L33.x.n, L33.y.n, 3, 0);
  1007.   }
  1008.   
  1009.   _plflush ();
  1010.   _pltext ();
  1011.   
  1012.   #
  1013.   # Increment the plot no. so that next time
  1014.   # we use the correct settings.
  1015.   #
  1016.   
  1017.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1018.   
  1019.   return P;
  1020. };
  1021.  
  1022. ##############################################################################
  1023. #
  1024. # Plot a 3-Dimensional graph. The data is composed in a list, with
  1025. # elements `x', `y', and `z'. x and y are single-dimension arrays
  1026. # (row or column matrices), and z is a two-dimensional array. The
  1027. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  1028. # the array x can be thought of a "row-labels", and the values of y
  1029. # can be thought of as "column-lables" for the 2-dimensioal array z.
  1030. #
  1031. # At present plmesh can plot 3 distinct lists. Each list may have
  1032. # different X, Y, and Z scales.
  1033. #
  1034. ##############################################################################
  1035.  
  1036. plmesh = function ( L31, L32, L33 )
  1037. {
  1038.   check_plot_object ();
  1039.   
  1040.   #
  1041.   # 1st check list contents
  1042.   #
  1043.   
  1044.   if (exist (L31)) { check_3d_list (L31); }
  1045.   if (exist (L32)) { check_3d_list (L32); }
  1046.   if (exist (L33)) { check_3d_list (L33); }
  1047.   
  1048.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1049.  
  1050.   #
  1051.   # Figure out the scale limits. 
  1052.   # Needs improvement!
  1053.   #
  1054.   
  1055.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  1056.   if (exist (L31)) 
  1057.   {
  1058.     XYZ_scales (L31.x, L31.y, L31.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  1059.     xmin = Xmin; xmax = Xmax;
  1060.     ymin = Ymin; ymax = Ymax;
  1061.     zmin = Zmin; zmax = Zmax;
  1062.   }
  1063.   if (exist (L32)) 
  1064.   {
  1065.     XYZ_scales (L32.x, L32.y, L32.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  1066.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  1067.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  1068.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  1069.   }   
  1070.   if (exist (L33)) 
  1071.   {
  1072.     XYZ_scales (L33.x, L33.y, L33.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  1073.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  1074.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  1075.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  1076.   }
  1077.  
  1078.   _plgra ();
  1079.   _plcol (1);
  1080.   _pllsty (1);
  1081.   _plfont (WIN.[P].font[p]);
  1082.   _plwid (WIN.[P].width[p]);
  1083.   
  1084.   # basex = 2; basey = 2; height = 4;
  1085.   xmin2d = -2.0; xmax2d = 2.0;
  1086.   ymin2d = -3.0; ymax2d = 5.0;
  1087.   
  1088.   _plenv (xmin2d, xmax2d, ymin2d, ymax2d, 0, -2);
  1089.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  1090.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  1091.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  1092.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  1093.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  1094.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  1095.  
  1096.   if (exist (L31))
  1097.   {
  1098.     if (find_char (WIN.[P].grid3x[p], "l"))
  1099.     { x = log10 (real (L31.x)); else x = real (L31.x); }
  1100.     if (find_char (WIN.[P].grid3y[p], "l"))
  1101.     { y = log10 (real (L31.y)); else y = real (L31.y); }
  1102.     if (find_char (WIN.[P].grid3z[p], "l"))
  1103.     { z = log10 (real (L31.z)); else z = real (L31.z); }
  1104.     
  1105.     _plcol (2);
  1106.     _plmesh (x, y, z, L31.x.n, L31.y.n, 3);
  1107.   }
  1108.   if (exist (L32))
  1109.   {
  1110.     if (find_char (WIN.[P].grid3x[p], "l"))
  1111.     { x = log10 (real (L32.x)); else x = real (L32.x); }
  1112.     if (find_char (WIN.[P].grid3y[p], "l"))
  1113.     { y = log10 (real (L32.y)); else y = real (L32.y); }
  1114.     if (find_char (WIN.[P].grid3z[p], "l"))
  1115.     { z = log10 (real (L32.z)); else z = real (L32.z); }
  1116.     
  1117.     _plcol (3);
  1118.     _pllsty (2);
  1119.     _plmesh (x, y, z, L32.x.n, L32.y.n, 3);
  1120.   }
  1121.   if (exist (L33)) 
  1122.   {
  1123.     if (find_char (WIN.[P].grid3x[p], "l"))
  1124.     { x = log10 (real (L33.x)); else x = real (L33.x); }
  1125.     if (find_char (WIN.[P].grid3y[p], "l"))
  1126.     { y = log10 (real (L33.y)); else y = real (L33.y); }
  1127.     if (find_char (WIN.[P].grid3z[p], "l"))
  1128.     { z = log10 (real (L33.z)); else z = real (L33.z); }
  1129.     
  1130.     _plcol (4);
  1131.     _pllsty (3);
  1132.     _plmesh (x, y, z, L33.x.n, L33.y.n, 3);
  1133.   }
  1134.  
  1135.   _plflush ();
  1136.   _pltext ();
  1137.   
  1138.   #
  1139.   # Increment the plot no. so that next time
  1140.   # we use the correct settings.
  1141.   #
  1142.   
  1143.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1144.   
  1145.   return P;
  1146. };
  1147.  
  1148. ##############################################################################
  1149. #
  1150. # Plot contours. The data is composed in a list, with
  1151. # elements `x', `y', and `z'. x and y are single-dimension arrays
  1152. # (row or column matrices), and z is a two-dimensional array. The
  1153. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  1154. # the array x can be thought of a "row-labels", and the values of y
  1155. # can be thought of as "column-lables" for the 2-dimensioal array z.
  1156. #
  1157. ##############################################################################
  1158.  
  1159. plcont = function ( CL )
  1160. {
  1161.   check_plot_object ();
  1162.   
  1163.   #
  1164.   # 1st check list contents
  1165.   #
  1166.   
  1167.   if (exist (CL)) { check_3d_list (CL); }
  1168.  
  1169.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1170.   
  1171.   #
  1172.   # Figure out the scale limits. 
  1173.   # Needs improvement!
  1174.   #
  1175.  
  1176.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  1177.   if (exist (CL)) 
  1178.   {
  1179.     XYZ_scales (CL.x, CL.y, CL.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  1180.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  1181.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  1182.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  1183.   }
  1184.  
  1185.   _plgra ();
  1186.   _plcol (1);
  1187.   _pllsty (1);
  1188.   _plfont (WIN.[P].font[p]);
  1189.   _plwid (WIN.[P].width[p]);
  1190.  
  1191.   #
  1192.   # Set up the 1st viewport for drawing the plot.
  1193.   #
  1194.  
  1195.   if (!subplot_f) 
  1196.   {
  1197.     _pladv (0);        # Advance 1 subplot
  1198.   else
  1199.     subplot_f = 0;     # The user has set the subplot
  1200.   }
  1201.  
  1202.   _plvpas (0.15, 0.75, 0.15, 0.85, WIN.[P].aspect[p]);
  1203.   # _plvpor (0.15, 0.75, 0.15, 0.85);
  1204.   _plwind (xmin, xmax, ymin, ymax);
  1205.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1206.  
  1207.   # Convert the data to log data if necessary.
  1208.   if (find_char (WIN.[P].gridx[p], "l"))
  1209.   { x = log10 (real (CL.x)); else x = real (CL.x); }
  1210.   if (find_char (WIN.[P].gridy[p], "l"))
  1211.   { y = log10 (real (CL.y)); else y = real (CL.y); }
  1212.   z = real (CL.z);
  1213.   
  1214.   if (exist (CL.clevel))
  1215.   {
  1216.     clevel = CL.clevel;
  1217.   else
  1218.     clevel = linspace(zmin, zmax, 10);
  1219.   }
  1220.  
  1221.   #
  1222.   # Draw the contours
  1223.   #
  1224.  
  1225.   l = 1;
  1226.   for (i in 1:clevel.n)
  1227.   {
  1228.     k = mod (i-1, 14) + 1;
  1229.     j = mod (i-1, 8) + 1;
  1230.     _pllsty(j);
  1231.     _plcol (1+k);
  1232.     if (_plcont (x, y, z, 1, CL.x.n, 1, CL.y.n, clevel[i]))
  1233.     {
  1234.       llevel[l] = clevel[i];
  1235.       l = l + 1;
  1236.     }
  1237.   }
  1238.  
  1239.   #
  1240.   # Reset color and draw the labels.
  1241.   #
  1242.  
  1243.   _plcol (1);
  1244.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1245.  
  1246.   #
  1247.   # Draw the contour legend. Use a new viewport to the right
  1248.   # of the contour plot.
  1249.   #
  1250.  
  1251.   #_plvpas (0.75, 1.0, 0.15, 0.85, WIN.[P].aspect[p]);
  1252.   _plvpor (0.75, 1.0, 0.15, 0.85);
  1253.   _plwind (0, 1, 0, 1);
  1254.  
  1255.   v = 1 - 1/(2*llevel.n);
  1256.  
  1257.   for (i in 1:llevel.n)
  1258.   {
  1259.     xl = [0.1, 0.2, 0.3]';
  1260.     yl = [v, v, v]';
  1261.     v = v - 1/llevel.n;
  1262.  
  1263.     k = mod (i-1, 14) + 1;
  1264.     j = mod (i-1, 8) + 1;
  1265.  
  1266.     _plcol (1+k);
  1267.     _pllsty (j);
  1268.  
  1269.     _plline (3, xl, yl);
  1270.     sprintf (stmp, "%.2g", llevel[i]);
  1271.     plptex (stmp, xl[3]+.1, yl[3], , , 0);
  1272.   }
  1273.  
  1274.   # Flush  and go back to text mode.
  1275.   _plflush ();
  1276.   _pltext ();
  1277.   
  1278.   #
  1279.   # Increment the plot no. so that next time
  1280.   # we use the correct settings.
  1281.   #
  1282.   
  1283.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1284.   
  1285.   return P;
  1286. };
  1287.  
  1288. ##############################################################################
  1289. #
  1290. # Plot 3-D lines, etc...
  1291. #
  1292.  
  1293. pl3d = function ( X, Y, Z, BR )
  1294. {
  1295.   local (X, Y, Z, BR)
  1296.   check_plot_object ();
  1297.   
  1298.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1299.  
  1300.   #
  1301.   # Some basic checks
  1302.   #
  1303.  
  1304.   if ((N = X.n) != Y.n) { error ("pl3d: X and Y must have same length"); }
  1305.   if (N != Z.n) { error ("pl3d: X and Z must have same length"); }
  1306.  
  1307.   if (!exist (BR)) { BR = N; }
  1308.   if (mod (N, BR) != 0) { error ("pl3d: X.n must be divisible by BR"); }
  1309.   iBR = int (N / BR);
  1310.   if (iBR == 1) { k = N; else k = BR; }
  1311.  
  1312.   #
  1313.   # Figure out the scale limits. 
  1314.   # Needs improvement!
  1315.   #
  1316.   
  1317.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  1318.   XYZ_scales (X, Y, Z, p, xmin, xmax, ymin, ymax, zmin, zmax);
  1319.  
  1320.   _plgra ();
  1321.   _plcol (1);
  1322.   _pllsty (1);
  1323.   _plfont (WIN.[P].font[p]);
  1324.   _plwid (WIN.[P].width[p]);
  1325.   
  1326.   if (!subplot_f) 
  1327.   {
  1328.     _pladv (0);        # Advance 1 subplot
  1329.     else
  1330.     subplot_f = 0;     # The user has set the subplot
  1331.   }
  1332.  
  1333.   if (find_char (WIN.[P].grid3x[p], "l"))
  1334.   { X = log10 (real (X)); else X = real (X); }
  1335.   if (find_char (WIN.[P].grid3y[p], "l"))
  1336.   { Y = log10 (real (Y)); else Y = real (Y); }
  1337.   if (find_char (WIN.[P].grid3z[p], "l"))
  1338.   { Z = log10 (real (Z)); else Z = real (Z); }
  1339.     
  1340.   # basex = 2; basey = 2; height = 4;
  1341.   xmin2d = -2.0; xmax2d = 2.0;
  1342.   ymin2d = -3.0; ymax2d = 5.0;
  1343.   
  1344.   if (WIN.[P].aspect[p] != 0)
  1345.   {
  1346.     _plvasp (WIN.[P].aspect[p]);
  1347.   else
  1348.     _plvsta ();
  1349.   }
  1350.  
  1351.   _plwind (xmin2d, xmax2d, ymin2d, ymax2d);
  1352.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  1353.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  1354.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  1355.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  1356.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  1357.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  1358.  
  1359.   _plcol (2);
  1360.   for (i in 1:iBR)
  1361.   {
  1362.     j = [(i-1)*k+1:i*k];
  1363.     _plline3 (k, X[j], Y[j], Z[j]);
  1364.   }
  1365.   _plflush ();
  1366.   _pltext ();
  1367.   
  1368.   #
  1369.   # Increment the plot no. so that next time
  1370.   # we use the correct settings.
  1371.   #
  1372.   
  1373.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1374.   
  1375.   return P;
  1376. };
  1377.  
  1378. ##############################################################################
  1379. #
  1380. # error bar plot
  1381. #
  1382.  
  1383. plerry = function (x, y, y_low, y_high)
  1384. {
  1385.   check_plot_object ();
  1386.   
  1387.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1388.   WIN.[P].desc.[p] = 1j;    // use own legend
  1389.   
  1390.   if (x.nr != y.nr || x.nr != y_low.nr || x.nr != y_high.nr) 
  1391.   {
  1392.     error(" Size inconsistent in plerry.");
  1393.   }
  1394.   _plgra ();
  1395.   _plcol (1);
  1396.   _pllsty (1);
  1397.   _plfont (WIN.[P].font[p]);
  1398.   _plwid (WIN.[P].width[p]);
  1399.   xy_scales ( real([x,y,y_low,y_high]), p, xmin, xmax, ymin, ymax );
  1400.   
  1401.   if (!subplot_f) 
  1402.   {
  1403.     _pladv (0);        # Advance 1 subplot
  1404.   else
  1405.     subplot_f = 0;     # The user has set the subplot
  1406.   }
  1407.  
  1408.   if (WIN.[P].aspect[p] != 0)
  1409.   {
  1410.     _plvasp (WIN.[P].aspect[p]);
  1411.   else
  1412.     _plvsta ();
  1413.   }
  1414.  
  1415.   _plwind (xmin, xmax, ymin, ymax);
  1416.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1417.  
  1418.   if (plot_matrix ( [x,y], p, 0, xmin, xmax, ymin, ymax, ymax-ymin ) < 0) 
  1419.   { 
  1420.     return -1; 
  1421.   }
  1422.  
  1423.   _plcol (3);
  1424.   _plerry(x.nr, x, y_low, y_high);
  1425.   _plcol (1);
  1426.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1427.   _plflush ();
  1428.   _pltext ();
  1429.   
  1430.   #
  1431.   # Increment the plot no. so that next time
  1432.   # we use the correct settings.
  1433.   #
  1434.   
  1435.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1436.   return P;      
  1437. };
  1438.  
  1439. ##############################################################################
  1440. #
  1441. # Plot a Histogram(s), from the columns of a matrix.
  1442. #
  1443. ##############################################################################
  1444.  
  1445. plhist = function ( M , nbin )
  1446. {
  1447.   check_plot_object ();
  1448.   
  1449.   if (!exist (nbin)) { nbin = 10; }
  1450.   
  1451.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1452.   np = M.nr;
  1453.   
  1454.   # Compute max/min values of data
  1455.   
  1456.   ymin = min (min (real (M)));
  1457.   ymax = max (max (real (M)));
  1458.   
  1459.   #
  1460.   # Check computed scale limits against user's
  1461.   #
  1462.   
  1463.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  1464.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  1465.  
  1466.   _plgra ();
  1467.   _plcol (1);
  1468.   _plfont (WIN.[P].font[p]);
  1469.   _plwid (WIN.[P].width[p]);
  1470.   
  1471.   for (i in 1:M.nc) 
  1472.   { 
  1473.     hscale[i] = hist_scales (M[;i], nbin);
  1474.   }  
  1475.  
  1476.   if (!subplot_f) {
  1477.     _pladv (0);        # Advance 1 subplot
  1478.   else
  1479.     subplot_f = 0;     # The user has set the subplot
  1480.   }
  1481.  
  1482.   if (WIN.[P].aspect[p] != 0)
  1483.   {
  1484.     _plvasp (WIN.[P].aspect[p]);
  1485.   else
  1486.     _plvsta ();
  1487.   }
  1488.  
  1489.   _plwind (ymin, ymax, 0, max (hscale));
  1490.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1491.  
  1492.   v = max (hscale);
  1493.   xmax = ymax;
  1494.   for (i in 1:M.nc)
  1495.   {
  1496.     k = mod (i, 14) + 1;
  1497.     _plcol (WIN.[P].color[p;k]);
  1498.     _plhist (np, real(M[;i]), ymin, ymax, nbin, 1);
  1499.     
  1500.     if (!any (any (WIN.[P].desc.[p] == 1j)))
  1501.     {
  1502.       # Use the default if necessary
  1503.       if (WIN.[P].desc.[p][1] == "default") 
  1504.       {
  1505.     desc = "c"+num2str(i);
  1506.       else if (WIN.[P].desc.[p].n >= i) {
  1507.     desc = WIN.[P].desc.[p][i];
  1508.       else
  1509.     # Not sure what to do, user has messed up.
  1510.     desc = "";
  1511.       } }
  1512.  
  1513.       v = v - max(hscale)/11;
  1514.       xl = (ymax-ymin)*[10.5/12, 11/12, 11.5/12]' + ymin;
  1515.       yl = [v, v, v]';
  1516.  
  1517.       _plline (3, xl, yl);
  1518.       plptex(desc, xl[1]-(ymax-ymin)/25, yl[3], , , 1);
  1519.     }
  1520.   }
  1521.  
  1522.   _plcol (1);
  1523.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1524.   _plflush ();
  1525.   _pltext ();
  1526.  
  1527.   #
  1528.   # Increment the plot no. so that next time
  1529.   # we use the correct settings.
  1530.   #
  1531.   
  1532.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1533.  
  1534.   return 1;
  1535. };
  1536.  
  1537. ##############################################################################
  1538. #
  1539. # Various support functions for the WIN list
  1540. #
  1541. ##############################################################################
  1542.  
  1543. #
  1544. # Replot
  1545. #
  1546.  
  1547. replot = function ( )
  1548. {
  1549.   check_plot_object ();
  1550.   _replot ();
  1551. };
  1552.  
  1553. ##############################################################################
  1554. #
  1555. # Set the X-axis label
  1556. #
  1557.  
  1558. xlabel = function ( xstr )
  1559. {
  1560.   check_plot_object ();
  1561.   if (!exist (xstr)) { xstr = ""; }
  1562.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1563.   WIN.[P].xlabel[i] = xstr;
  1564. };
  1565.  
  1566. ##############################################################################
  1567. #
  1568. # Set the Y-axis label
  1569. #
  1570.  
  1571. ylabel = function ( xstr )
  1572. {
  1573.   check_plot_object ();
  1574.   if (!exist (xstr)) { xstr = ""; }
  1575.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1576.   WIN.[P].ylabel[i] = xstr;
  1577. };
  1578.  
  1579. ##############################################################################
  1580. #
  1581. # Set the Z-axis label
  1582. #
  1583.  
  1584. zlabel = function ( xstr )
  1585. {
  1586.   check_plot_object ();
  1587.   if (!exist (xstr)) { xstr = ""; }
  1588.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1589.   WIN.[P].zlabel[i] = xstr;
  1590. };
  1591.  
  1592. ##############################################################################
  1593. #
  1594. # Set the plot-title
  1595. #
  1596.  
  1597. pltitle = function ( xstr )
  1598. {
  1599.   check_plot_object ();
  1600.   if (!exist (xstr)) { xstr = ""; }
  1601.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1602.   WIN.[P].title[p] = xstr;
  1603. };
  1604.  
  1605. ##############################################################################
  1606. #
  1607. # Set the scale limits.
  1608. #
  1609.  
  1610. plimits = function ( xmin, xmax, ymin, ymax, zmin, zmax )
  1611. {
  1612.   check_plot_object ();
  1613.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1614.  
  1615.   if (exist (xmin)) 
  1616.   {
  1617.     WIN.[P].xmin[i] = xmin;
  1618.   else
  1619.     WIN.[P].xmin[i] = 1j;
  1620.   }
  1621.   if (exist (xmax)) 
  1622.   { 
  1623.     WIN.[P].xmax[i] = xmax;
  1624.   else
  1625.     WIN.[P].xmax[i] = 1j;
  1626.   }
  1627.  
  1628.   if (exist (ymin)) 
  1629.   {
  1630.     WIN.[P].ymin[i] = ymin;
  1631.   else
  1632.     WIN.[P].ymin[i] = 1j;
  1633.   }
  1634.   if (exist (ymax)) 
  1635.   {
  1636.     WIN.[P].ymax[i] = ymax;
  1637.   else
  1638.     WIN.[P].ymax[i] = 1j;
  1639.   }
  1640.  
  1641.   if (exist (zmin)) 
  1642.   {
  1643.     WIN.[P].zmin[i] = zmin;
  1644.   else
  1645.     WIN.[P].zmin[i] = 1j;
  1646.   }
  1647.   if (exist (zmax)) 
  1648.   {
  1649.     WIN.[P].zmax[i] = zmax;
  1650.   else
  1651.     WIN.[P].zmax[i] = 1j;
  1652.   }
  1653. };
  1654.  
  1655. ##############################################################################
  1656. #
  1657. # Set 2-D grid styles. A not-so-friendly interface.
  1658. #
  1659.  
  1660. plgrid = function ( sty_x, sty_y )
  1661. {
  1662.   check_plot_object ();
  1663.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1664.  
  1665.   if (exist (sty_x)) 
  1666.   { 
  1667.     if (class (sty_x) == "string")
  1668.     {
  1669.       WIN.[P].gridx[i] = sty_x;
  1670.     else
  1671.       error ("plgrid: requires string argument GRID_STY_X");
  1672.     }
  1673.   else
  1674.     WIN.[P].gridx[i] = grid_x_default;
  1675.   }
  1676.   if (exist (sty_y)) 
  1677.   { 
  1678.     if (class (sty_y) == "string")
  1679.     {
  1680.       WIN.[P].gridy[i] = sty_y;
  1681.     else
  1682.       error ("plgrid: requires string argument GRID_STY_Y");
  1683.     }
  1684.   else
  1685.     WIN.[P].gridy[i] = grid_y_default;
  1686.   }
  1687. };
  1688.  
  1689. ##############################################################################
  1690. #
  1691. # Set 3-D grid (axis) styles
  1692. #
  1693.  
  1694. plgrid3 = function ( sty_x, sty_y, sty_z )
  1695. {  
  1696.   check_plot_object ();
  1697.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1698.   if (exist (sty_x)) 
  1699.   { 
  1700.     if (class (sty_x) == "string")
  1701.     {
  1702.       WIN.[P].grid3x[i] = sty_x;
  1703.     else
  1704.       error ("plgrid3: requires string argument GRID_STY_X");
  1705.     }
  1706.   else
  1707.     WIN.[P].grid3x[i] = grid_3x_default;
  1708.   }
  1709.   if (exist (sty_y)) 
  1710.   { 
  1711.     if (class (sty_y) == "string")
  1712.     {
  1713.       WIN.[P].grid3y[i] = sty_y;
  1714.     else
  1715.       error ("plgrid3: requires string argument GRID_STY_Y");
  1716.     }
  1717.   else
  1718.     WIN.[P].grid3y[i] = grid_3y_default;
  1719.   }
  1720.   if (exist (sty_z)) 
  1721.   { 
  1722.     if (class (sty_z) == "string")
  1723.     {
  1724.       WIN.[P].grid3z[i] = sty_z;
  1725.     else
  1726.       error ("plgrid3: requires string argument GRID_STY_Z");
  1727.     }
  1728.   else
  1729.     WIN.[P].grid3z[i] = grid_3z_default;
  1730.   }
  1731. };
  1732.  
  1733. ##############################################################################
  1734. #
  1735. # A friendlier interface to changing 2-D grid/axis
  1736. # styles.
  1737. #
  1738.  
  1739. plaxis = function ( X_STR, Y_STR )
  1740. {
  1741.   check_plot_object ();
  1742.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1743.   
  1744.   if (exist (X_STR))
  1745.   {
  1746.     if (X_STR == "log") { WIN.[P].gridx[i] = "bcngstl"; }
  1747.   else
  1748.     WIN.[P].gridx[i] = grid_x_default;
  1749.   }
  1750.   
  1751.   if (exist (Y_STR))
  1752.   {
  1753.     if (Y_STR == "log") { WIN.[P].gridy[i] = "bcngstlv"; }
  1754.   else
  1755.     WIN.[P].gridy[i] = grid_y_default;
  1756.   }
  1757.   return P;
  1758. };
  1759.  
  1760. ##############################################################################
  1761. #
  1762. # Various internal support functions. Eventually these will be static.
  1763. #
  1764. ##############################################################################
  1765.  
  1766. #
  1767. # Find the X or Y scale limits .
  1768. # M can be a multi-column matrix, all columns
  1769. # will be used.
  1770. #
  1771.  
  1772. x_scales = function ( M, p, xmin, xmax )
  1773. {  
  1774.   #
  1775.   # 1st check for un-plottable data
  1776.   #
  1777.   
  1778.   if (any (any (isinf (M))))
  1779.   { error ("plot: cannot plot Infs"); }
  1780.   if (any (any (isnan (M))))
  1781.   { error ("plot: cannot plot NaNs"); }
  1782.   
  1783.   xmin = min (min (M));
  1784.   xmax = max (max (M));
  1785.   
  1786.   #
  1787.   # Check computed scale limits against user's
  1788.   #
  1789.   
  1790.   if (WIN.[P].xmin[p] != 1j) { xmin = WIN.[P].xmin[p]; }
  1791.   if (WIN.[P].xmax[p] != 1j) { xmax = WIN.[P].xmax[p]; }
  1792.  
  1793.   #
  1794.   # Check for potential errors
  1795.   #
  1796.   
  1797.   if (xmin == xmax) 
  1798.   { 
  1799.     # As good a guess as any
  1800.     xmin = xmin - 1;
  1801.     xmax = xmax + 1;
  1802.   }
  1803.   
  1804.   #
  1805.   # Finally, adjust if log-scales
  1806.   #
  1807.   
  1808.   if (find_char (WIN.[P].gridx[p], "l"))
  1809.   {
  1810.     if (xmin <= 0 || xmax <= 0) { error ("cannot plot log(x<=0)"); }
  1811.     xmin = log10 (xmin);
  1812.     xmax = log10 (xmax);
  1813.   }
  1814.   
  1815.   return 1;
  1816. };
  1817.  
  1818. y_scales = function ( M, p, xmin, xmax )
  1819. {
  1820.   
  1821.   #
  1822.   # 1st check for un-plottable data
  1823.   #
  1824.   
  1825.   if (any (any (isinf (M))))
  1826.   { error ("plot: cannot plot Infs"); }
  1827.   if (any (any (isnan (M))))
  1828.   { error ("plot: cannot plot NaNs"); }
  1829.   
  1830.   xmin = min (min (M));
  1831.   xmax = max (max (M));
  1832.   
  1833.   #
  1834.   # Check computed scale limits against user's
  1835.   #
  1836.   
  1837.   if (WIN.[P].ymin[p] != 1j) { xmin = WIN.[P].ymin[p]; }
  1838.   if (WIN.[P].ymax[p] != 1j) { xmax = WIN.[P].ymax[p]; }
  1839.  
  1840.   #
  1841.   # Check for potential errors
  1842.   #
  1843.   
  1844.   if (xmin == xmax) 
  1845.   { 
  1846.     # As good a guess as any
  1847.     xmin = xmin - 1;
  1848.     xmax = xmax + 1;
  1849.   }
  1850.   
  1851.   #
  1852.   # Finally, adjust if log-scales
  1853.   #
  1854.   
  1855.   if (find_char (WIN.[P].gridy[p], "l"))
  1856.   {
  1857.     if (xmin <= 0 || xmax <= 0) { error ("cannot plot log(y<=0)"); }
  1858.     xmin = log10 (xmin);
  1859.     xmax = log10 (xmax);
  1860.   }
  1861.   
  1862.   return 1;
  1863. };
  1864.  
  1865. z_scales = function ( M, p, xmin, xmax )
  1866. {
  1867.   
  1868.   #
  1869.   # 1st check for un-plottable data
  1870.   #
  1871.   
  1872.   if (any (any (isinf (M))))
  1873.   { error ("plot: cannot plot Infs"); }
  1874.   if (any (any (isnan (M))))
  1875.   { error ("plot: cannot plot NaNs"); }
  1876.   
  1877.   xmin = min (min (M));
  1878.   xmax = max (max (M));
  1879.   
  1880.   #
  1881.   # Check computed scale limits against user's
  1882.   #
  1883.   
  1884.   if (WIN.[P].zmin[p] != 1j) { xmin = WIN.[P].zmin[p]; }
  1885.   if (WIN.[P].zmax[p] != 1j) { xmax = WIN.[P].zmax[p]; }
  1886.  
  1887.   #
  1888.   # Check for potential errors
  1889.   #
  1890.   
  1891.   if (xmin == xmax) 
  1892.   { 
  1893.     # As good a guess as any
  1894.     xmin = xmin - 1;
  1895.     xmax = xmax + 1;
  1896.   }
  1897.   
  1898.   #
  1899.   # Finally, adjust if log-scales
  1900.   #
  1901.   
  1902.   if (find_char (WIN.[P].gridz[p], "l"))
  1903.   {
  1904.     if (xmin <= 0 || xmax <= 0) { error ("plot: cannot plot log(z<=0)"); }
  1905.     xmin = log10 (xmin);
  1906.     xmax = log10 (xmax);
  1907.   }
  1908.   
  1909.   return 1;
  1910. };
  1911.  
  1912. ##############################################################################
  1913. #
  1914. # Find the X and Y scales for a single matrix. (OLD)
  1915. #
  1916.  
  1917. xy_scales = function ( M, p, xmin, xmax, ymin, ymax )
  1918. {  
  1919.   #
  1920.   # 1st check for un-plottable data
  1921.   #
  1922.   
  1923.   if (any (any (isinf (M))))
  1924.   { error ("plot: cannot plot infs"); }
  1925.   if (any (any (isnan (M))))
  1926.   { error ("plot: cannot plot NaNs"); }
  1927.   
  1928.   if (M.nc == 1)
  1929.   {
  1930.     xmin = 1;
  1931.     xmax = M.nr;
  1932.     ymin = min (M);
  1933.     ymax = max (M);
  1934.   else
  1935.     xmin = min (M[;1]);
  1936.     xmax = max (M[;1]);
  1937.     ymin = min (min (M[;2:M.nc]));
  1938.     ymax = max (max (M[;2:M.nc]));
  1939.   }
  1940.   
  1941.   #
  1942.   # Check computed scale limits against user's
  1943.   #
  1944.   
  1945.   if (WIN.[P].xmin[p] != 1j) { xmin = WIN.[P].xmin[p]; }
  1946.   if (WIN.[P].xmax[p] != 1j) { xmax = WIN.[P].xmax[p]; }
  1947.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  1948.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  1949.   
  1950.   #
  1951.   # Check for potential errors
  1952.   #
  1953.   
  1954.   if (xmin == xmax) 
  1955.   { 
  1956.     xmin = xmin - 1;
  1957.     xmax = xmax + 1;
  1958.   }
  1959.   
  1960.   if (ymin == ymax)
  1961.   {
  1962.     ymin = ymin - 1;
  1963.     ymax = ymax + 1;
  1964.   }
  1965.   
  1966.   #
  1967.   # Finally, adjust if log-scales
  1968.   #
  1969.   
  1970.   if (find_char (WIN.[P].gridx[p], "l"))
  1971.   {
  1972.     if (xmin <= 0 || xmax <= 0) { error ("plot: cannot plot log <= 0"); }
  1973.     xmin = log10 (xmin);
  1974.     xmax = log10 (xmax);
  1975.   }
  1976.   if (find_char (WIN.[P].gridy[p], "l"))
  1977.   {
  1978.     if (ymin <= 0 || ymax <= 0) { error ("plot: cannot plot log <= 0"); }
  1979.     ymin = log10 (ymin);
  1980.     ymax = log10 (ymax);
  1981.   }
  1982.   
  1983.   return 1;
  1984. };
  1985.  
  1986. ##############################################################################
  1987. #
  1988. # Find the X, Y and Z scales for a single matrix.
  1989. #
  1990.  
  1991. XYZ_scales = function ( X, Y, Z, p, xmin, xmax, ymin, ymax, zmin, zmax )
  1992. {
  1993.   # X - scale
  1994.   if (any (any (isinf (X))))
  1995.   { error ("cannot plot infs"); }
  1996.   if (any (any (isnan (X))))
  1997.   { error ("cannot plot NaNs"); }
  1998.   
  1999.   xmin = min (real (X));
  2000.   xmax = max (real (X));
  2001.   
  2002.   # Y - scale
  2003.   if (any (any (isinf (Y))))
  2004.   { error ("cannot plot infs"); }
  2005.   if (any (any (isnan (Y))))
  2006.   { error ("cannot plot NaNs"); }
  2007.   
  2008.   ymin = min (real (Y));
  2009.   ymax = max (real (Y));
  2010.   
  2011.   # Z - scale
  2012.   if (any (any (isinf (Y))))
  2013.   { error ("cannot plot infs"); }
  2014.   if (any (any (isnan (Y))))
  2015.   { error ("cannot plot NaNs"); }
  2016.   
  2017.   zmin = min (min (real (Z)));
  2018.   zmax = max (max (real (Z)));
  2019.   
  2020.   #
  2021.   # Check computed scale limits against user's
  2022.   #
  2023.   
  2024.   if (WIN.[P].xmin[p] != 1j) { xmin = WIN.[P].xmin[p]; }
  2025.   if (WIN.[P].xmax[p] != 1j) { xmax = WIN.[P].xmax[p]; }
  2026.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  2027.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  2028.   if (WIN.[P].zmin[p] != 1j) { zmin = WIN.[P].zmin[p]; }
  2029.   if (WIN.[P].zmax[p] != 1j) { zmax = WIN.[P].zmax[p]; }
  2030.   
  2031.   #
  2032.   # Check for potential errors
  2033.   #
  2034.   
  2035.   if (xmin == xmax) 
  2036.   { 
  2037.     # As good a guess as any
  2038.     xmin = xmin - 1;
  2039.     xmax = xmax + 1;
  2040.   }
  2041.   
  2042.   if (ymin == ymax) 
  2043.   { 
  2044.     # As good a guess as any
  2045.     ymin = ymin - 1;
  2046.     ymax = ymax + 1;
  2047.   }
  2048.   
  2049.   if (zmin == zmax) 
  2050.   { 
  2051.     # As good a guess as any
  2052.     zmin = zmin - 1;
  2053.     zmax = zmax + 1;
  2054.   }
  2055.   
  2056.   #
  2057.   # Finally, adjust if log-scales
  2058.   #
  2059.   
  2060.   if (find_char (WIN.[P].grid3x[p], "l"))
  2061.   {
  2062.     if (xmin <= 0 || xmax <= 0) { error ("plot: cannot plot log(x<=0)"); }
  2063.     xmin = log10 (xmin);
  2064.     xmax = log10 (xmax);
  2065.   }
  2066.   
  2067.   if (find_char (WIN.[P].grid3y[p], "l"))
  2068.   {
  2069.     if (ymin <= 0 || ymax <= 0) { error ("plot: cannot plot log(y<=0)"); }
  2070.     ymin = log10 (ymin);
  2071.     ymax = log10 (ymax);
  2072.   }
  2073.   
  2074.   if (find_char (WIN.[P].grid3z[p], "l"))
  2075.   {
  2076.     if (zmin <= 0 || zmax <= 0) { error ("plot: cannot plot log(z<=0)"); }
  2077.     zmin = log10 (zmin);
  2078.     zmax = log10 (zmax);
  2079.   }
  2080.   
  2081.   return 1;
  2082. };
  2083.  
  2084. ##############################################################################
  2085. #
  2086. # Find the X and Y scales for a list of matrices
  2087. #
  2088.  
  2089. list_scales = function ( data, key, p, Xmin, Xmax, Ymin, Ymax )
  2090. {
  2091.   once = 1;
  2092.   
  2093.   for (i in members (data))
  2094.   {
  2095.     M = real (data.[i]);
  2096.     if (class (M) != "num") { continue; }
  2097.     
  2098.     if (abs (key) > M.nc)
  2099.     {
  2100.       error_1 ("plot: KEY argument > M.nc");
  2101.     }
  2102.     
  2103.     #
  2104.     # 1st check for un-plottable data
  2105.     #
  2106.     
  2107.     if (any (any (isinf (M))))
  2108.     { error ("plot: cannot plot infs"); }
  2109.     if (any (any (isnan (M))))
  2110.     { error ("plot: cannot plot NaNs"); }
  2111.     
  2112.     k = find ((1:M.nc) != abs (key));
  2113.     if (key > 0)
  2114.     {
  2115.       if (M.nc != 1)
  2116.       {
  2117.     x_scales ( real(M)[;key], p, xmin, xmax );
  2118.     y_scales ( real(M)[;k],   p, ymin, ymax );
  2119.       else
  2120.     x_scales ( (1:M.nr)', p, xmin, xmax );
  2121.     y_scales ( real(M),   p, ymin, ymax );
  2122.       }
  2123.     else if (key < 0) {
  2124.       x_scales ( real(M)[;k],        p, xmin, xmax );
  2125.       y_scales ( real(M)[;abs(key)], p, ymin, ymax );
  2126.     else
  2127.       x_scales ( (1:M.nr)', p, xmin, xmax );
  2128.       y_scales ( real(M),   p, ymin, ymax );
  2129.     } }
  2130.  
  2131.     if (once) 
  2132.     { 
  2133.       Xmin = xmin; Xmax = xmax; Ymin = ymin; Ymax = ymax; 
  2134.       once = 0; 
  2135.     }
  2136.     if (xmin < Xmin) { Xmin = xmin; }
  2137.     if (xmax > Xmax) { Xmax = xmax; }
  2138.     if (ymin < Ymin) { Ymin = ymin; }
  2139.     if (ymax > Ymax) { Ymax = ymax; }
  2140.   }
  2141.   
  2142.   return 1;
  2143. };
  2144.  
  2145. ##############################################################################
  2146. #
  2147. # Find the maximum number of elements in a bin for a single 
  2148. # column matrix.
  2149. #
  2150.  
  2151. hist_scales = function ( data, nbin )
  2152. {
  2153.   dmin = min (real (data));
  2154.   dmax = max (real (data));
  2155.   dbin = linspace (dmin, dmax, nbin+1);
  2156.   binval = zeros (nbin, 1);
  2157.   
  2158.   for (i in 1:nbin)
  2159.   {
  2160.     binval[i] = length (find (data >= dbin[i] && data < dbin[i+1]));
  2161.   }
  2162.   
  2163.   return max (binval);
  2164. };
  2165.  
  2166. ##############################################################################
  2167. #
  2168. # Plot the columns of a matrix (core function)
  2169. #
  2170. # Notes: This is the core function for plotting a matrix. If the
  2171. # matrix is a single column, then the matrix elements are plotted
  2172. # versus the row numbers. If it is a multi-column matrix, then
  2173. # columns 2:N are plotted versus column 1.
  2174. #
  2175. # p, K, k and l are indices for plot features.
  2176. # p: the current plot index (the plot #)
  2177. # K: usually 0. This index is used to start of the line style and
  2178. # color index (k = color index, l = line-style index). This is mostly
  2179. # used by plot_list, which may call plot_matrix repeatedly.
  2180. # k: the line color index. This value determines the line color used
  2181. # for each column of data. If K = 0, then k goes like 2:14, then
  2182. # flops back to 1:14.
  2183. # l: the line style inex. This value determines the line style used
  2184. # for each column of data - not the line-type (points, or lines). If
  2185. # K = 0, then l goes like 2:8, then flops back to 1:8.
  2186. #
  2187. ##############################################################################
  2188.  
  2189. plot_matrix = function ( M, key, p, K, xmin, xmax, ymin, ymax, v )
  2190. {
  2191.   np = M.nr;
  2192.   
  2193.   if (M.nc == 1)
  2194.   {
  2195.     x = 1:M.nr;
  2196.     y = real (M);
  2197.     k = mod (1+K, 14) + 1;
  2198.     l = mod (1+K, 8);
  2199.     
  2200.     if (find_char (WIN.[P].gridx[p], "l"))
  2201.     { x = log10 (x); }
  2202.     if (find_char (WIN.[P].gridy[p], "l"))
  2203.     { y = log10 (y); }
  2204.     
  2205.     _plcol (WIN.[P].color[p;k]);
  2206.     _pllsty (WIN.[P].lstyle[p;l]);
  2207.     
  2208.     if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2209.     {
  2210.       _plline (M.nr, x, y);
  2211.     else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2212.       _plpoin (M.nr, x, y, WIN.[P].pstyle[p;l]);
  2213.     else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2214.       _plline (M.nr, x, y);
  2215.       _plpoin (M.nr, x, y, WIN.[P].pstyle[p;l]);
  2216.     else {
  2217.       _plline (M.nr, x, y);
  2218.     }}}}
  2219.  
  2220.     #
  2221.     # Now do the legend 
  2222.     #
  2223.     
  2224.     if (!any (any (WIN.[P].desc.[p] == 1j)))
  2225.     {
  2226.       # Use the default if necessary
  2227.       if (WIN.[P].desc.[p][1] == "default") 
  2228.       {
  2229.     desc = "c1";
  2230.       else if (WIN.[P].desc.[p].n >= k-1) {
  2231.     desc = WIN.[P].desc.[p][k-1];
  2232.       else
  2233.     # Not sure what to do, user has messed up.
  2234.     desc = "";
  2235.       } }
  2236.              
  2237.       v = v - (ymax-ymin)/11;
  2238.       xl = (xmax-xmin)*[10.5/12, 11/12, 11.5/12]' + xmin;
  2239.       yl = [v, v, v]' + ymin;
  2240.       
  2241.       if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2242.       {
  2243.     _plline (3, xl, yl);
  2244.       else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2245.     _plpoin (3, xl, yl, WIN.[P].pstyle[p;l]);
  2246.       else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2247.     _plline (3, xl, yl);
  2248.     _plpoin (3, xl, yl, WIN.[P].pstyle[p;l]);
  2249.       } } }
  2250.  
  2251.       plptex(desc, xl[1]-(xmax-xmin)/25, yl[3], , , 1);
  2252.       
  2253.     }
  2254.  
  2255.   else
  2256.  
  2257.     #
  2258.     # Check for large column dimension
  2259.     #
  2260.     
  2261.     if (M.nc > 3*M.nr)
  2262.     {
  2263.       printf (" Plot %i columns and %i rows, are you sure (y/n) ? "...
  2264.                , M.nc, M.nr);
  2265.       ans = getline ("stdin");
  2266.       if (ans.[1] != "y") { return -1; }
  2267.     }
  2268.     
  2269.     ki = find ((1:M.nc) != abs (key));
  2270.     for (i in ki)
  2271.     {
  2272.       if (key > 0)
  2273.       {
  2274.     x = real (M[;key]);
  2275.     y = real (M[;i]);
  2276.       else if (key < 0) {
  2277.     x = real (M[;i]);
  2278.     y = real (M[;abs(key)]);
  2279.       else
  2280.     x = (1:M.nr)';
  2281.     y = real (M[;i]);
  2282.       } }
  2283.  
  2284.       # Check for log scales, adjust if necessary
  2285.       if (find_char (WIN.[P].gridx[p], "l"))
  2286.       { x = log10 (x); }
  2287.       if (find_char (WIN.[P].gridy[p], "l"))
  2288.       { y = log10 (y); }
  2289.       
  2290.       k = mod (i-1 + K, 14) + 1;
  2291.       l = mod (8 + i-2 + K, 8) + 1;
  2292.       
  2293.       _plcol (WIN.[P].color[p;k]);
  2294.       _pllsty (WIN.[P].lstyle[p;l]);
  2295.       
  2296.       if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2297.       {
  2298.     _plline (np, x, y);
  2299.       else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2300.     _plpoin (np, x, y, WIN.[P].pstyle[p;l]);
  2301.       else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2302.     _plline (np, x, y);
  2303.     _plpoin (np, x, y, WIN.[P].pstyle[p;l]);
  2304.       else {
  2305.     _plline (np, x, y);
  2306.       }}}}
  2307.  
  2308.       #
  2309.       # Now do the legend 
  2310.       #
  2311.       
  2312.       if (!any (any (WIN.[P].desc.[p] == 1j)))
  2313.       {
  2314.     # Use the default if necessary
  2315.     if (WIN.[P].desc.[p][1] == "default") 
  2316.     {
  2317.       desc = "c" + num2str (i);
  2318.         else if (WIN.[P].desc.[p].n >= k-1) {
  2319.       desc = WIN.[P].desc.[p][k-1];
  2320.         else
  2321.       # Not sure what to do, user has messed up.
  2322.       desc = "";
  2323.         }}
  2324.              
  2325.     v = v - (ymax-ymin)/11;
  2326.     xl = (xmax-xmin)*[10.5/12, 11/12, 11.5/12]' + xmin;
  2327.     yl = [v, v, v]' + ymin;
  2328.     
  2329.     if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2330.     {
  2331.       _plline (3, xl, yl);
  2332.         else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2333.       _plpoin (3, xl, yl, WIN.[P].pstyle[p;l]);
  2334.         else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2335.       _plline (3, xl, yl);
  2336.       _plpoin (3, xl, yl, WIN.[P].pstyle[p;l]);
  2337.         }}}
  2338.     
  2339.     plptex(desc, xl[1]-(xmax-xmin)/25, yl[3], , , 1);
  2340.     
  2341.       }
  2342.     }
  2343.   }
  2344.   
  2345.   return k-1;
  2346. };
  2347.  
  2348. ##############################################################################
  2349. #
  2350. # Plot all of the matrices in a list on the same plot
  2351. #
  2352.  
  2353. plot_list = function ( L, key, p, xmin, xmax, ymin, ymax )
  2354. {
  2355.   k = 0;
  2356.   v = ymax - ymin;
  2357.   
  2358.   #
  2359.   # Sort out the list members
  2360.   #
  2361.  
  2362.   sl = list_sort (L);
  2363.  
  2364.   # Plot the list members with numeric labels 1st.
  2365.   if (exist (sl.num))
  2366.   {
  2367.     for (i in sl.num)
  2368.     {
  2369.       M = L.[i];
  2370.       if (class (M) != "num") { continue; }
  2371.       if ((k = plot_matrix (M, key, p, k, xmin, xmax, ymin, ymax, v)) < 0) 
  2372.       { 
  2373.     return k; 
  2374.       }
  2375.     }
  2376.   }
  2377.  
  2378.   # Now plot the list members with string labels.
  2379.   if (exist (sl.char))
  2380.   {
  2381.     for (i in sl.char)
  2382.     {
  2383.       M = L.[i];
  2384.       if (class (M) != "num") { continue; }
  2385.       if ((k = plot_matrix (M, key, p, k, xmin, xmax, ymin, ymax, v)) < 0) 
  2386.       { 
  2387.     return k; 
  2388.       }
  2389.     }
  2390.   }
  2391.   return 1;
  2392. };
  2393.  
  2394. ##############################################################################
  2395. #
  2396. # Check the elements of LIST.
  2397. # LIST must contain elements `x', `y',
  2398. # and `z'
  2399. #
  2400.  
  2401. check_3d_list = function ( LIST )
  2402. {
  2403.   #
  2404.   # Check existence and types
  2405.   #
  2406.   
  2407.   if (class (LIST) != "list") {
  2408.     error ("plot3: argument must be a list");
  2409.   }
  2410.   if (!exist (LIST.x)) {
  2411.     error ("plot3: arg must contain `x' member");
  2412.   else if (class (LIST.x) != "num") {
  2413.     error ("plot3: x must be numeric");
  2414.   } }
  2415.   if (!exist (LIST.y)) {
  2416.     error ("plot3: arg must contain `y' member");
  2417.   else if (class (LIST.y) != "num") {
  2418.     error ("plot3: y must be numeric"); 
  2419.   } }
  2420.   if (!exist (LIST.z)) {
  2421.     error ("plot3: arg must contain `z' member");
  2422.   else if (class (LIST.z) != "num") {
  2423.     error ("plot3: z must be numeric");
  2424.   } }
  2425.  
  2426.   #
  2427.   # Check sizes
  2428.   #
  2429.   
  2430.   if (LIST.x.n != LIST.z.nr) 
  2431.   {
  2432.     error ("plot3: x.n != z.nr");
  2433.   }
  2434.   
  2435.   if (LIST.y.n != LIST.z.nc) 
  2436.   {
  2437.     error ("plot3: y.n != z.nc");
  2438.   }
  2439.   
  2440. };
  2441.  
  2442. ##############################################################################
  2443. #
  2444. # A special type of histogram plot.
  2445. #
  2446.  
  2447. plhistx = function ( M , nbin )
  2448. {
  2449.   check_plot_object ();
  2450.   
  2451.   if (!exist (nbin)) { nbin = 10; }
  2452.   
  2453.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  2454.   np = M.nr;
  2455.   
  2456.   # Compute max/min values of data
  2457.   
  2458.   ymin = min (min(real (M)));
  2459.   ymax = max (max(real (M)));
  2460.   
  2461.   #
  2462.   # Check computed scale limits against user's
  2463.   #
  2464.   
  2465.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  2466.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  2467.   
  2468.   _plgra ();
  2469.   _plcol (15);
  2470.   _plfont (WIN.[P].font[p]);
  2471.   _plwid (WIN.[P].width[p]);
  2472.   
  2473.   dbin = (linspace (ymin, ymax, nbin+1))';
  2474.   for (j in 1:M.nc) 
  2475.   {
  2476.     // counting
  2477.     for (i in 1:nbin) 
  2478.     {
  2479.       binval[i;j] = length (find (M[;j] >= dbin[i] && M[;j] < dbin[i+1]));
  2480.     }
  2481.   }
  2482.   
  2483.   if (!subplot_f) {
  2484.     _pladv (0);        # Advance 1 subplot
  2485.   else
  2486.     subplot_f = 0;     # The user has set the subplot
  2487.   }
  2488.  
  2489.   if (WIN.[P].aspect[p] != 0)
  2490.   {
  2491.     _plvasp (WIN.[P].aspect[p]);
  2492.   else
  2493.     _plvsta ();
  2494.   }
  2495.  
  2496.   xmin = 0;
  2497.   xmax =  max(max(binval));
  2498.   _plwind (ymin, ymax, xmin, xmax);
  2499.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  2500.  
  2501.   #
  2502.   # Now reorganize dbin and binval so we plot points in
  2503.   # the middle of the bins.
  2504.   #
  2505.  
  2506.   delbin = abs(dbin[2] - dbin[1]);
  2507.   dbin = (linspace (ymin+delbin/2, ymax-delbin/2, nbin))';
  2508.   dbin = [ymin ; dbin ; ymax];
  2509.   binval = [zeros(1,binval.nc); binval; zeros(1,binval.nc)];
  2510.  
  2511.   v = xmax;
  2512.   for (i in 1:M.nc)
  2513.   {
  2514.     k = mod (i, 14) + 1;
  2515.     l = mod (i,  8) + 1;
  2516.     _plcol (WIN.[P].color[p;k]);
  2517.     _pllsty (WIN.[P].lstyle[p;l]);
  2518.     
  2519.     if      (get_style (WIN.[P].style.[p], k-1) == "line") 
  2520.     {
  2521.       _plline (nbin+2, dbin, binval[;i]);
  2522.     else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2523.       _plpoin (nbin+2, dbin, binval[;i], WIN.[P].pstyle[p]+k);
  2524.     else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2525.       _plline (nbin+2, dbin, binval[;i]);
  2526.       _plpoin (nbin+2, dbin, binval[;i], WIN.[P].pstyle[p]+k);     
  2527.     } } }
  2528.  
  2529.     // write legend around upper-right corner.
  2530.     // it is better to have user to choose location for legend.
  2531.     
  2532.     if (!any (any (WIN.[P].desc.[p] == 1j)))
  2533.     {
  2534.       # Use the default if necessary
  2535.       if (WIN.[P].desc.[p][1] == "default") 
  2536.       {
  2537.     desc = "c"+num2str(i);
  2538.       else if (WIN.[P].desc.[p].n >= i) {
  2539.       desc = WIN.[P].desc.[p][i];
  2540.       else
  2541.     # Not sure what to do, user has messed up.
  2542.     desc = "";
  2543.       } }
  2544.  
  2545.       v = v - (xmax)/11;
  2546.       xt = (ymax-ymin)*[10.5/12, 11/12, 11.5/12]' + ymin;
  2547.       yt = [v, v, v]';
  2548.       
  2549.       if      (get_style (WIN.[P].style.[p], k-1) == "line") 
  2550.       {
  2551.     _plline (3, xt, yt);
  2552.       else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2553.     _plpoin (3, xt, yt, WIN.[P].pstyle[p]+k);
  2554.       else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2555.     _plline (3, xt, yt);
  2556.     _plpoin (3, xt, yt, WIN.[P].pstyle[p]+k);
  2557.       } } }
  2558.  
  2559.       plptex(desc, xt[1]-(ymax-ymin)/25, yt[3], , , 1);
  2560.     }
  2561.   }
  2562.   
  2563.   _plcol (15);
  2564.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  2565.   _plflush ();
  2566.   _pltext ();
  2567.   
  2568.   #
  2569.   # Increment the plot no. so that next time
  2570.   # we use the correct settings.
  2571.   #
  2572.   
  2573.   WIN.[P].subplot = WIN.[P].subplot + 1;
  2574.   
  2575.   return 1;
  2576. };
  2577.  
  2578.  
  2579. ##############################################################################
  2580. #
  2581. # Create a legend in the current plot window
  2582. #
  2583. # if pobj.desc.[p] = inf()        no legend
  2584. # if pobj.desc.[p] = "default"        default ("c1", "c2", ...)
  2585. # if pobj.desc.[p] = "string"        use "string" as description
  2586. #
  2587.  
  2588. #
  2589. # Set the current plot legend string
  2590. #
  2591.  
  2592. plegend = function ( LEGEND )
  2593. {
  2594.   check_plot_object ();
  2595.   
  2596.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  2597.   
  2598.   if (!exist (LEGEND)) 
  2599.   {
  2600.     WIN.[P].desc.[p] = 1j;
  2601.     return P;
  2602.   }
  2603.   
  2604.   if (class (LEGEND) == "string")
  2605.   {
  2606.     WIN.[P].desc.[p] = LEGEND;
  2607.   }
  2608.   
  2609.   return P;
  2610. };
  2611.  
  2612. set3d = function (bx, by, h)
  2613. {
  2614.   if (!exist (bx)) { basex = 2; else basex = bx; }
  2615.   if (!exist (by)) { basey = 2; else basey = by; }
  2616.   if (!exist (h)) { height = 4; else height = h; }
  2617. };
  2618.